#!/usr/bin/env bash
set -euo pipefail

# build.sh - 一键构建 Go 二进制（支持交叉构建）
# Usage:
#   ./build.sh                 # 构建本机目标
#   ./build.sh -t linux/amd64  # 指定目标
#   ./build.sh -t "linux/amd64,darwin/amd64" -s  # 多目标并 strip

SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
cd "$SCRIPT_DIR"

OUT_DIR=dist
mkdir -p "$OUT_DIR"

TARGETS=""
STRIP=0
VER_OVERRIDE=""
NAME=osd_cpu_bind

print_help(){
  cat <<'EOF'
Usage: build.sh [options]

Options:
  -t, --targets    comma-separated list of GOOS/GOARCH (e.g. linux/amd64,linux/arm64)
  -s, --strip      run strip on produced binaries when available
  -n, --name       output binary base name (default: osd_cpu_bind)
  -v, --version    override version string
  -h, --help       show this help

By default builds for the host GOOS/GOARCH.
Binaries are emitted into the dist/ directory.
EOF
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    -t|--targets)
      TARGETS="$2"; shift 2;;
    -s|--strip)
      STRIP=1; shift 1;;
    -n|--name)
      NAME="$2"; shift 2;;
    -v|--version)
      VER_OVERRIDE="$2"; shift 2;;
    -h|--help)
      print_help; exit 0;;
    *)
      echo "Unknown arg: $1"; print_help; exit 1;;
  esac
done

if [[ -z "$TARGETS" ]]; then
  # build for host
  GOOS=$(go env GOOS)
  GOARCH=$(go env GOARCH)
  TARGETS="${GOOS}/${GOARCH}"
fi

IFS=',' read -r -a arr <<< "$TARGETS"
## Ensure Go modules are available and dependencies fetched
ensure_go_modules() {
  if [[ -f go.mod ]]; then
    echo "go.mod found, running 'go mod tidy' to ensure dependencies are present"
    tidy_out=$(mktemp)
    if go mod tidy 2>"$tidy_out"; then
      rm -f "$tidy_out"
      return
    else
      echo "go mod tidy failed; checking error"
      if grep -q "invalid go version" "$tidy_out" || grep -q "must match format" "$tidy_out"; then
        echo "Detected incompatible go version directive. Trying legacy versions of golang.org/x/crypto"
        for v in v0.43.0 v0.42.0 v0.41.0 v0.40.0 v0.39.0; do
          echo "Attempt pin golang.org/x/crypto@$v"
          if go get golang.org/x/crypto@$v 2>/dev/null; then
            echo "Pinned golang.org/x/crypto@$v, retry tidy"
            if go mod tidy 2>/dev/null; then
              echo "tidy succeeded with golang.org/x/crypto@$v"; break
            fi
          fi
        done
      else
        echo "go mod tidy failed with:"
        sed -n '1,200p' "$tidy_out" >&2 || true
      fi
      rm -f "$tidy_out"
      return
    fi
  fi

  # Try to derive module path from git remote if available
  if command -v git >/dev/null 2>&1; then
    REMOTE_URL=$(git config --get remote.origin.url 2>/dev/null || true)
  else
    REMOTE_URL=""
  fi

  if [[ -n "$REMOTE_URL" ]]; then
    # Normalize remote URL to module path e.g. https://gitee.com/user/repo.git -> gitee.com/user/repo
    MODULE_PATH=$(echo "$REMOTE_URL" | sed -E 's#^https?://##; s#^git@##; s#[:]#/#g; s#\.git$##')
    echo "Initializing go module with inferred path: $MODULE_PATH"
    go mod init "$MODULE_PATH" || true
  else
    # fallback: init with directory name
    MODULE_PATH=$(basename "$PWD")
    echo "No git remote found, initializing go module with local name: $MODULE_PATH"
    go mod init "$MODULE_PATH" || true
  fi

  echo "Running 'go mod tidy' to download dependencies"
  tidy_out=$(mktemp)
  if go mod tidy 2>"$tidy_out"; then
    rm -f "$tidy_out"
  else
    echo "go mod tidy failed; checking error"
    if grep -q "invalid go version" "$tidy_out" || grep -q "must match format" "$tidy_out"; then
      echo "Detected incompatible go version directive. Trying legacy versions of golang.org/x/crypto"
      for v in v0.43.0 v0.42.0 v0.41.0 v0.40.0 v0.39.0; do
        echo "Attempt pin golang.org/x/crypto@$v"
        if go get golang.org/x/crypto@$v 2>/dev/null; then
          echo "Pinned golang.org/x/crypto@$v, retry tidy"
          if go mod tidy 2>/dev/null; then
            echo "tidy succeeded with golang.org/x/crypto@$v"; break
          fi
        fi
      done
    else
      echo "go mod tidy failed with:"
      sed -n '1,200p' "$tidy_out" >&2 || true
    fi
    rm -f "$tidy_out"
  fi
}

ensure_go_modules

for t in "${arr[@]}"; do
  t=$(echo "$t" | xargs)
  if [[ "$t" == "" ]]; then
    continue
  fi
  IFS='/' read -r goos goarch <<< "$t"
  outname="$NAME"
  if [[ "$goos" != "windows" ]]; then
    binpath="$OUT_DIR/${outname}-${goos}-${goarch}"
  else
    binpath="$OUT_DIR/${outname}-${goos}-${goarch}.exe"
  fi

  echo "Building $t -> $binpath"

  env GOOS="$goos" GOARCH="$goarch" go build -o "$binpath" -v . || { echo "go build failed for $t"; exit 1; }

  if [[ $STRIP -eq 1 ]]; then
    if command -v strip >/dev/null 2>&1; then
      echo "Stripping $binpath"
      strip "$binpath" || true
    else
      echo "strip not found, skipping strip for $binpath"
    fi
  fi

  if [[ -n "$VER_OVERRIDE" ]]; then
    # write a .version file next to binary
    echo "$VER_OVERRIDE" > "${binpath}.version"
  fi

  sha256sum "$binpath" > "${binpath}.sha256" || true
done

echo "All done. Artifacts in $OUT_DIR"
